home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1996
/
MacHack 1996.toast
/
Hacks
/
Hacks ’89
/
Gas Gauge
/
Example CDEF
/
custom_cdef.c
Wrap
C/C++ Source or Header
|
1989-06-16
|
20KB
|
661 lines
#include "StdInclude.h"
/* NB: There is little or no error checking for bad handle, pointers, etc. Perhaps there should */
/* be but it is unclear what should be done if there is an error. Exit? Call DebugStr? */
/* Perhaps I should try and check my own region handles and rect (frame, empty, etc.) since */
/* it is my responsibility to check these but even if I made a mistake, what should I do? */
/* There is no good way to get an error back to the programmer. */
typedef short int16;
typedef long int32;
typedef unsigned short uint16;
typedef unsigned long uint32;
/* at last! CDEF stuff */
typedef struct cntl_rgns /* data structure for regions in control, handle to this stored in contrlData field */
{
RgnHandle frame;
RgnHandle empty;
RgnHandle full;
RgnHandle indicator;
Rect ind_rect;
} cntl_rgns;
typedef cntl_rgns * cntl_rgns_ptr;
typedef cntl_rgns_ptr * cntl_rgns_hdl;
typedef struct thumb_lim {
/* fubar type struct used by ctl manager for showing limits of "thumb" dragging */
Rect limitRect, slopRect;
int16 axis;
} thumb_lim;
/* prototypes for custom stuff */
void CDEF_draw_cntl(ControlHandle,int32);
void CDEF_buttons(ControlHandle);
void CDEF_frame(ControlHandle);
void CDEF_indicator(ControlHandle);
void CDEF_disabled_cntl(ControlHandle);
Point CDEF_ind_endpt(ControlHandle, int16);
int32 CDEF_test_cntl(ControlHandle, int32);
void CDEF_calc_rgns_cntl(ControlHandle, int32);
void CDEF_all_rgns (ControlHandle, cntl_rgns_hdl);
void CDEF_init_cntl (ControlHandle);
void CDEF_disp_cntl (ControlHandle);
int32 CDEF_drag_cntl (ControlHandle,int32);
void CDEF_pos_cntl (ControlHandle,int16,int16);
void CDEF_thumb_cntl (ControlHandle,int32);
Point CDEF_find_center (ControlHandle);
int16 CDEF_value_to_angle ( ControlHandle, int16 );
int16 CDEF_angle_to_value ( ControlHandle, int16 );
void CDEF_ind_rgn ( ControlHandle, int16, RgnHandle );
#define SysFontSiz 12
#define ENABLED 0
#define DISABLED 255
#define ALL 0
#define TITLE 1
#define INDBITMASK 0x80000000
#define INDBYTECLEAR 0x00FFFFFF
#define NO_CONSTRAINT 0
#define RETURN
pascal int32 main (varCode,theCtl,message,param)
int16 varCode;
ControlHandle theCtl;
int16 message;
int32 param;
{
int32 retn_value;
GrafPtr oldPort;
/* custom control to implement a gas gauge */
HLock ( (Handle)theCtl );
GetPort ( &oldPort );
SetPort ( (**theCtl).contrlOwner );
retn_value = (int32)0;
switch (message)
{
case drawCntl:
CDEF_draw_cntl ( theCtl, param );
break;
case testCntl:
retn_value = CDEF_test_cntl ( theCtl, param );
break;
case calcCRgns:
CDEF_calc_rgns_cntl ( theCtl, param );
break;
case initCntl:
CDEF_init_cntl ( theCtl );
break;
case dispCntl:
CDEF_disp_cntl ( theCtl );
break;
case dragCntl:
retn_value = CDEF_drag_cntl ( theCtl, param );
break;
case posCntl:
CDEF_pos_cntl ( theCtl, LoWord ( param ), HiWord ( param ) );
break;
case thumbCntl:
CDEF_thumb_cntl ( theCtl, param );
break;
case autoTrack:
break;
}
SetPort ( oldPort );
HUnlock ( (Handle)theCtl );
return ( retn_value );
}
Point CDEF_find_center ( the_cntl )
ControlHandle the_cntl;
{
Rect cntl_rect;
Point center;
/* return the center of the control rectangle */
cntl_rect = (**the_cntl).contrlRect;
SetPt ( ¢er, cntl_rect.left+(cntl_rect.right-cntl_rect.left)/2, cntl_rect.top+(cntl_rect.bottom-cntl_rect.top)/2 );
return ( center );
}
void CDEF_draw_cntl(the_cntl,param)
ControlHandle the_cntl;
int32 param;
{
PenState ps;
int16 radius;
if ((**the_cntl).contrlVis == 0) /* invisible so don't draw */
RETURN;
GetPenState(&ps); /* to save against any hiliting */
switch( param )
{
default: /* this is necessary because of Control Manager bug: */
/* CM calls me with part code == 255?! */
case ALL:
CDEF_frame(the_cntl);
CDEF_buttons(the_cntl);
CDEF_indicator(the_cntl);
/* CDEF_cntl_draw_title(the_cntl); add this later */
break;
case inThumb:
CDEF_indicator (the_cntl);
break;
case inUpButton:
case inDownButton:
CDEF_buttons(the_cntl);
break;
}
if ((**the_cntl).contrlHilite == DISABLED)
CDEF_disabled_cntl(the_cntl);
SetPenState(&ps); /* no side effects in grafport */
}
void CDEF_buttons(the_cntl)
ControlHandle the_cntl; /* assumed to be locked */
{
Point the_center;
Rect cntl_rect;
int16 radius;
int16 old_text_size;
Style old_text_face;
int16 old_text_font;
PenState ps;
RgnHandle but_rgn_hdl;
GrafPtr cur_port;
/* check hiliting and if title is hilited, draw it so */
GetPenState ( &ps );
GetPort ( &cur_port );
old_text_size = cur_port->txSize;
old_text_font = cur_port->txFont;
old_text_face = cur_port->txFace;
TextSize ( 12 ); /* default size */
TextFont ( 0 ); /* default font */
TextFace ( 0 );
the_center = CDEF_find_center ( the_cntl );
/* draw the buttons - boxed '0' and '1' for now */
cntl_rect = (**the_cntl).contrlRect;
if ( cntl_rect.bottom - cntl_rect.top > cntl_rect.right - cntl_rect.left )
radius = the_center.h - cntl_rect.left;
else
radius = the_center.v - cntl_rect.top;
but_rgn_hdl = (**(cntl_rgns_hdl)(**the_cntl).contrlData).empty;
EraseRgn ( but_rgn_hdl ); /* clear out the old */
MoveTo ( the_center.h, the_center.v );
Move ( -(radius-2), 0 );
PenSize ( 2, 2 );
Line( 5, 0 ); /* hash mark */
PenSize ( 1, 1 );
Move( 7, 5 ); /* text is above an to the right of penpos */
DrawChar('0');
FrameRgn ( but_rgn_hdl ); /* box the text */
if ((**the_cntl).contrlHilite == inUpButton)
InvertRgn ( but_rgn_hdl );
/* draw the full indicator */
but_rgn_hdl = (**(cntl_rgns_hdl)(**the_cntl).contrlData).full;
EraseRgn ( but_rgn_hdl ); /* erase the old */
MoveTo ( the_center.h, the_center.v );
Move ( (radius-8), 0 );
PenSize ( 2, 2 );
Line( 5, 0 ); /* hash mark */
PenSize ( 1, 1 );
Move( -(10+CharWidth('1')), 5 );
DrawChar ( '1' );
FrameRgn ( but_rgn_hdl );
if ((**the_cntl).contrlHilite == inDownButton)
InvertRgn ( but_rgn_hdl );
/* draw the 1/2 full mark */
MoveTo(the_center.h,the_center.v-(radius-8));
PenSize ( 2, 2 );
Line( 0, -5 );
PenSize ( 1, 1 );
TextSize ( old_text_size ); /* restore text size before leaving */
TextFont ( old_text_font ); /* restore text font before leaving */
TextFace ( old_text_face ); /* restore text face before leaving */
SetPenState ( &ps ); /* restore penstate before leaving */
}
void CDEF_frame(the_cntl)
ControlHandle the_cntl; /* assumed to be locked */
{
PenState ps;
GetPenState ( &ps );
PenSize ( 2, 2 );
/* EraseRgn ( (**((cntl_rgns_hdl)(**the_cntl).contrlData)).frame );*/
FrameRgn ( (**((cntl_rgns_hdl)(**the_cntl).contrlData)).frame );
SetPenState ( &ps );
}
void CDEF_indicator ( the_cntl )
ControlHandle the_cntl; /* assumed to be locked */
{
RgnHandle ind_rgn_hdl;
Rect ind_rect;
ind_rect = (**((cntl_rgns_hdl)(**the_cntl).contrlData)).ind_rect;
EraseOval ( &ind_rect ); /* clear out old indicator */
ind_rgn_hdl = (**((cntl_rgns_hdl)(**the_cntl).contrlData)).indicator;
CDEF_ind_rgn ( the_cntl, (**the_cntl).contrlValue, ind_rgn_hdl );
if ((**the_cntl).contrlHilite == inThumb)
PaintRgn ( ind_rgn_hdl );
else
FrameRgn ( ind_rgn_hdl );
}
void CDEF_disabled_cntl(the_cntl)
ControlHandle the_cntl; /* assumed to be locked */
{
PenState ps;
Pattern gray_pat;
GetPenState(&ps);
GetIndPattern ( &gray_pat, sysPatListID, 4 );
PenPat(gray_pat);
PenMode(patBic);
PaintOval(&(**the_cntl).contrlRect);
SetPenState(&ps);
}
Point CDEF_ind_endpt ( the_ctl, value )
ControlHandle the_ctl;
int16 value;
{
int16 angle, radius;
Fixed radians, temp1, temp2;
Point endpt, the_center;
Rect ind_rect;
Fract trig_val;
/* calculates the endpt of the indicator of the control */
ind_rect = (**(cntl_rgns_hdl)(**the_ctl).contrlData).ind_rect;
the_center = CDEF_find_center ( the_ctl );
radius = ind_rect.right - the_center.h;
angle = CDEF_value_to_angle ( the_ctl, value ); /* convert it to degrees counterclockwise */
radians = FixDiv ( Long2Fix ( (long)angle ), Long2Fix ( 45L ) ); /* now divide by 90 to find out how many Pi/4's there are */
radians = FixMul ( FixAtan2 ( 1L, 1L ), radians ); /* FixATan2(1,1) == Pi/4 */
temp1 = Frac2Fix ( FracCos ( radians ) );
temp2 = Long2Fix ( (long)radius );
endpt.h = (int16)Fix2Long ( FixMul ( temp1, temp2 ) );
temp1 = Frac2Fix ( FracSin ( radians ) );
endpt.v = (int16)Fix2Long ( FixMul ( temp1, temp2 ) ); /* to move from the center out by r*cos(theta), r*sin(theta) */
AddPt ( the_center, &endpt );
MoveTo ( endpt.h, endpt.v );
return ( endpt );
}
int32 CDEF_test_cntl(the_cntl,param)
ControlHandle the_cntl;
int32 param;
{
cntl_rgns_hdl my_cntl_rgns; /* handle of control's custom regions */
int16 the_angle,cur_angle;
Point the_point,cur_pt;
Rect ind_rect;
/* this routine test where the mouse was down as passed in the_point and returns the */
/* part code for the part of the control referenced by the_cntl */
if ((**the_cntl).contrlHilite == DISABLED) /* inactive control so return a 0 to indicatew nothing selected */
RETURN( 0L );
SetPt(&the_point,LoWord(param),HiWord(param));
my_cntl_rgns = (cntl_rgns_hdl)(**the_cntl).contrlData; /* handle to my data structure for control */
if ( !PtInRgn( the_point, (**my_cntl_rgns).frame ) )
return ( 0L ); /* if point is outside of control frame, return 0 to indicate nothing hit */
if ( PtInRgn( the_point, (**my_cntl_rgns).empty ) )
return ( (long)inUpButton ); /* because the '0' maps to scrollbar up button */
if ( PtInRgn ( the_point,(**my_cntl_rgns).full ) )
return ( (long)inDownButton ); /* because the '1' maps to scrollbar down button */
if ( PtInRgn ( the_point,(**my_cntl_rgns).indicator ) )
return ( (long)inThumb ); /* because arrow maps to scrollbar thumb */
/* now, if none of the above, check for page_up/down */
/* first check to see if it is area above and to right of E or above and left of F */
ind_rect = (**(cntl_rgns_hdl)(**the_cntl).contrlData).ind_rect;
InsetRect ( &ind_rect, 7, 7 );
PtToAngle( &ind_rect, the_point, &the_angle );
if ( the_angle < 270 && the_angle > 90 )
return ( 0L ); /* nohit because point is outside "active area" of control */
cur_pt = CDEF_ind_endpt ( the_cntl, (**the_cntl).contrlValue );
PtToAngle ( &ind_rect, cur_pt, &cur_angle );
/* now check to see if in page_up or page_down */
the_angle = (the_angle+90) % 360; /* to rotate angles to avoid angle "wrap" at 0 degrees */
cur_angle = (cur_angle+90) % 360; /* to rotate angles to avoid angle "wrap" at 0 degrees */
if ( the_angle<cur_angle )
return ( (long)inPageUp ); /* becuase point to left of indicator corresponds to scrollbar page up */
else
return ( (long)inPageDown ); /* becuase point to right of indicator corresponds to scrollbar page down */
}
int16 CDEF_value_to_angle ( the_ctl, the_value )
ControlHandle the_ctl;
int16 the_value;
{
int16 min_value, max_value;
/* return the associated angle for a value within the_ctl */
min_value = (**the_ctl).contrlMin;
max_value = (**the_ctl).contrlMax;
if (max_value-min_value == 0 )
return ( 0 );
else
return ( 180 + (the_value - min_value)*180/(max_value-min_value) );
}
int16 CDEF_angle_to_value ( the_ctl, the_angle )
ControlHandle the_ctl;
int16 the_angle;
{
int16 mid_value, min_value, max_value;
/* convert an angle to a value for the given control */
min_value = (**the_ctl).contrlMin;
max_value = (**the_ctl).contrlMax;
mid_value = (max_value+min_value)/2;
if ( the_angle <= 90 )
return ( mid_value + the_angle*(max_value-mid_value)/90 );
else
{
if ( the_angle >= 270 )
return ( mid_value - ((360 - the_angle) * (mid_value-min_value))/90 );
else
return ( min_value ); /* really an error, but what are ya gonna do? */
}
}
void CDEF_calc_rgns_cntl( the_cntl, param )
ControlHandle the_cntl;
int32 param;
{
/* calculate the control region or indicator region */
/* may want to add control title later on */
if (BitAnd(param, INDBITMASK )) /* if this bit is set, only indicator rgn is desired */
{
param = BitAnd ( param, INDBYTECLEAR );
CDEF_ind_rgn ( the_cntl, (**the_cntl).contrlValue, (**((cntl_rgns_hdl)(**the_cntl).contrlData)).indicator );
CopyRgn( (**((cntl_rgns_hdl)(**the_cntl).contrlData)).indicator, (RgnHandle)param );
}
else /* entire control region */
{
CDEF_all_rgns ( the_cntl, (cntl_rgns_hdl)(**the_cntl).contrlData );
CopyRgn ( (RgnHandle)param, (**((cntl_rgns_hdl)(**the_cntl).contrlData)).frame );
}
}
void CDEF_all_rgns ( the_cntl, the_cntl_rgns )
ControlHandle the_cntl;
cntl_rgns_hdl the_cntl_rgns;
{
FontInfo font_info;
Rect the_cntl_rect, the_trect;
Point the_center;
Point indicator;
int16 width, height;
/* calculate or recalculate regions specific to this control */
GetFontInfo (&font_info);
HLock ( (Handle)the_cntl_rgns );
the_cntl_rect = (**the_cntl).contrlRect;
the_center = CDEF_find_center ( the_cntl );
/* calculate "empty" button region */
SetRect ( &the_trect, the_cntl_rect.left+11, the_center.v-10, the_cntl_rect.left+10+font_info.widMax, the_center.v+10);
SetEmptyRgn ( (**the_cntl_rgns).empty );
OpenRgn();
FrameRect ( &the_trect );
CloseRgn ( (**the_cntl_rgns).empty );
/* calculate "full" button region */
SetRect ( &the_trect, the_cntl_rect.right-9-font_info.widMax, the_center.v-10, the_cntl_rect.right-10, the_center.v+10);
SetEmptyRgn ( (**the_cntl_rgns).full );
OpenRgn();
FrameRect ( &the_trect );
CloseRgn ( (**the_cntl_rgns).full );
/* calculate indicator rectangle */
width = the_cntl_rect.right - the_cntl_rect.left;
height = the_cntl_rect.bottom - the_cntl_rect.top;
if ( width > height )
SetRect ( &(**the_cntl_rgns).ind_rect, the_center.h-height/2, the_center.v-height/2, the_center.h+height/2, the_center.v+height/2 );
else
SetRect ( &(**the_cntl_rgns).ind_rect, the_center.h-width/2, the_center.v-width/2, the_center.h+width/2, the_center.v+width/2 );
InsetRect ( &(**the_cntl_rgns).ind_rect, 25, 25 );
/* calculate the indicator regions */
CDEF_ind_rgn ( the_cntl, (**the_cntl).contrlValue, (**the_cntl_rgns).indicator );
/* calculate control frame */
SetEmptyRgn ( (**the_cntl_rgns).frame );
OpenRgn();
FrameOval ( &(**the_cntl).contrlRect );
CloseRgn ( (**the_cntl_rgns).frame );
HUnlock ( (Handle)the_cntl_rgns );
}
void CDEF_ind_rgn ( the_cntl, value, the_rgn )
ControlHandle the_cntl;
int16 value;
RgnHandle the_rgn;
{
Point the_center, the_end, base_pt;
Rect ind_rect;
int16 the_angle;
/* calculate indicator region */
the_center = CDEF_find_center ( the_cntl );
the_angle = CDEF_value_to_angle ( the_cntl, value );
if ( the_angle < 240 || the_angle > 300 ) /* set up base of indicator based on angle */
{ /* if angle more horizontal, make base vert */
SetPt ( &base_pt, the_center.h, the_center.v-5 );
the_center.v += 5;
}
else /* else make it more horizontal */
{ /* this horsing around keeps the indicator */
SetPt ( &base_pt, the_center.h+5, the_center.v ); /* from disappearing */
the_center.h -= 5;
}
/* define region */
the_end = CDEF_ind_endpt( the_cntl, value ); /* move to end of indicator */
SetEmptyRgn ( the_rgn ); /* release region memory */
OpenRgn();
LineTo ( base_pt.h, base_pt.v );
LineTo ( the_center.h, the_center.v );
LineTo ( the_end.h, the_end.v );
CloseRgn( the_rgn ); /* save region into region passed in */
}
void CDEF_init_cntl ( the_cntl )
ControlHandle the_cntl;
{
cntl_rgns_hdl my_rgns;
/* initialize regions for this control */
my_rgns = (cntl_rgns_hdl)NewHandle ( sizeof ( cntl_rgns ) );
if ( my_rgns != NULL )
{
HLock ( (Handle)my_rgns );
(**my_rgns).frame = NewRgn();
(**my_rgns).empty = NewRgn();
(**my_rgns).full = NewRgn();
(**my_rgns).indicator = NewRgn();
HUnlock ( (Handle)my_rgns );
(**the_cntl).contrlData = (Handle)my_rgns;
CDEF_all_rgns ( the_cntl, (cntl_rgns_hdl)(**the_cntl).contrlData );
}
}
void CDEF_disp_cntl ( the_cntl )
ControlHandle the_cntl;
{
cntl_rgns_hdl my_rgns;
/* dispose of control regions */
my_rgns = (cntl_rgns_hdl)(**the_cntl).contrlData;
if ( my_rgns != NULL )
{
HLock ( (Handle)my_rgns );
if ( (**my_rgns).frame != NULL )
DisposeRgn ( (**my_rgns).frame );
if ( (**my_rgns).full != NULL )
DisposeRgn ( (**my_rgns).full );
if ( (**my_rgns).empty != NULL )
DisposeRgn ( (**my_rgns).empty );
if ( (**my_rgns).indicator != NULL )
DisposeRgn ( (**my_rgns).indicator );
HUnlock ( (Handle)my_rgns );
DisposeRgn ( my_rgns );
}
}
int32 CDEF_drag_cntl ( the_cntl, param )
ControlHandle the_cntl;
int32 param;
{
PenState ps;
Rect ind_rect;
Point center, cur_pt, start_pt;
int16 angle, value;
RgnHandle ghost_rgn;
Pattern gray_pat;
/* drag either the control or the indicator around */
if ( param != NULL ) /* drag indicator */
{
GetPenState ( &ps ); /* save penstate so we don't have ghosty-ink */
ghost_rgn = NewRgn (); /* region for ghosty indicator outline */
ind_rect = (**(cntl_rgns_hdl)(**the_cntl).contrlData).ind_rect;
center = CDEF_find_center ( the_cntl );
start_pt = CDEF_ind_endpt ( the_cntl, (**the_cntl).contrlValue );
HiliteControl ( the_cntl, inThumb ); /* hilite indicator */
/* draw "ghosty-gray" indicator */
PenSize ( 1,1 );
PenMode ( notPatXor ); /* this line and the next are the.. */
GetIndPattern ( &gray_pat, sysPatListID, 4 );
PenPat ( gray_pat ); /* ghosty-gray ink!! */
do /* drag until user lets go */
{
GetMouse ( &cur_pt );
PtToAngle ( &ind_rect, cur_pt, &angle ); /* convert cursor position to angle */
if ( !(angle > 90 && angle < 270) )
{
value = CDEF_angle_to_value ( the_cntl, angle );
CDEF_ind_rgn ( the_cntl, value, ghost_rgn );
PaintRgn ( ghost_rgn ); /* paint ghosty-gray indicator */
PaintRgn ( ghost_rgn ); /* unpaint ghosty-gray indicator */
}
}
while ( StillDown () );
PenNormal ();
(**the_cntl).contrlHilite = 0;
if ( angle > 90 && angle < 270 )
{
SysBeep ( 5 );
cur_pt = start_pt;
}
SubPt ( start_pt, &cur_pt ); /* pos_cntl expects relative offset */
CDEF_pos_cntl ( the_cntl, cur_pt.h, cur_pt.v ); /* move the indicator and update value */
DisposeRgn ( ghost_rgn ); /* release ghosty-gray indicator region */
SetPenState ( &ps ); /* restore penstate now we're done */
return ( 1L ); /* non-null retn means custom drag */
}
else
return ( NULL );
}
void CDEF_pos_cntl ( the_cntl, x, y )
ControlHandle the_cntl;
int16 x,y;
{
PenState ps;
Rect ind_rect;
Point old_pt, new_pt;
int16 the_angle;
uint16 new_value;
/* position the indicator at new location and update contrlValue according */
/* to relative offset stored in param field */
GetPenState ( &ps );
ind_rect = (**(cntl_rgns_hdl)(**the_cntl).contrlData).ind_rect;
/* EraseOval ( &ind_rect );*/
old_pt = CDEF_ind_endpt( the_cntl, (**the_cntl).contrlValue ); /* moves pen to end of indicator */
SetPt ( &new_pt, old_pt.h+x, old_pt.v+y );
PtToAngle ( &ind_rect, new_pt, &the_angle ); /* get indicator angle based on new_pt */
new_value = CDEF_angle_to_value ( the_cntl, the_angle ); /* reset contrlValue to new ind location */
(**the_cntl).contrlValue = new_value;
CDEF_ind_rgn ( the_cntl, (**the_cntl).contrlValue, (**(cntl_rgns_hdl)(**the_cntl).contrlData).indicator ); /* recalc region */
CDEF_indicator ( the_cntl ); /* draw indicator in new position */
SetPenState ( &ps ); /* reset penstate and get out of Dodge */
}
void CDEF_thumb_cntl ( the_cntl, param )
ControlHandle the_cntl;
int32 param;
{
Rect temp_rect;
/* calculate limits of movement for the "thumb" */
temp_rect = (**(cntl_rgns_hdl)(**the_cntl).contrlData).ind_rect;
temp_rect.bottom = (temp_rect.bottom - temp_rect.top)/2;
((thumb_lim *)param)->limitRect = temp_rect;
((thumb_lim *)param)->slopRect = temp_rect;
((thumb_lim *)param)->axis = NO_CONSTRAINT;
}